using System.Collections.Generic;
using UnityEngine;
using System;

namespace Super
{
	public class TimerManager : BaseSingle<TimerManager>
	{
		private PriorityQueue<TimerNode> timerQueue = new PriorityQueue<TimerNode>();
		private Dictionary<object, List<TimerNode>> gameDatas = new Dictionary<object, List<TimerNode>>();

		private void Update()
		{

			UpdateQueue();
		}

		/// <summary>
		/// 更新时间器，检查优先级最高的时间器
		/// 如果时间器在取消注册集合里，则从集合中取消，检查下一个
		/// 时间器结束，执行结束回调，检查下一个
		/// 时间器间隔结束，执行间隔回调，再次注册，检查下一个
		/// </summary>
		private void UpdateQueue()
		{
			bool overIntervalEndTime = false;
			bool overEndTime = false;
			if (timerQueue.TryPeek(out TimerNode node))
			{
				if (node.intervalCallBack != null && node.nextIntervalEndTime <= Time.time)
				{
					overIntervalEndTime = true;
				}
				if (node.endCallBack != null && node.endTime <= Time.time)
				{
					overEndTime = true;
				}
			}

			if (overIntervalEndTime || overEndTime)
			{
				timerQueue.Dequeue();
				if (overEndTime)
				{
					node?.endCallBack(node);
				}
				else if (overIntervalEndTime)
				{
					node.UpdateIntervalEndTime();
					node?.intervalCallBack(node);
					timerQueue.Enqueue(node);
				}
				UpdateQueue();
			}
		}

		/* ****************************  时间器相关  ****************************** */
		/// <summary>
		/// 注册时间器
		/// </summary>
		/// <param name="node"></param>
		public static void Register(object target, TimerNode node)
		{
			Ins.timerQueue.Enqueue(node);
			AddGameDatas(target, node);
		}

		public static void RegisterAndResetTime(object target, TimerNode node)
		{
			UnRegister(target, node);
			node.ResetEndTime();
			Register(target, node);
		}

		/// <summary>
		/// 取消注册时间器
		/// </summary>
		/// <param name="node"></param>
		public static void UnRegister(object target, TimerNode node)
		{
			if (node == null) return;
			if (target == null) return;

			Ins.timerQueue.Delete(node);
			if (Ins.gameDatas.TryGetValue(target, out List<TimerNode> timerNodes))
			{
				timerNodes.Remove(node);
			}
		}

		/// <summary>
		/// 取消实例上的所有时间器
		/// </summary>
		/// <param name="target"></param>
		public static void UnRegisterAll(object target)
		{
			if (target == null)
				return;

			if (Ins.gameDatas.ContainsKey(target))
			{
				var timerNodes = new List<TimerNode>(Ins.gameDatas[target]);
				if (timerNodes.Count > 0)
				{
					foreach (var item in timerNodes)
					{
						UnRegister(target, item);
					}
				}
			}
			Ins.gameDatas.Remove(target);
		}

		private static void AddGameDatas(object target, TimerNode node)
		{
			if (Ins.gameDatas.TryGetValue(target, out List<TimerNode> timerNodes))
			{
				timerNodes.Add(node);
			}
			else
			{
				timerNodes = new List<TimerNode>() { node };
				Ins.gameDatas.Add(target, timerNodes);
			}
		}
	}
}
